home *** CD-ROM | disk | FTP | other *** search
- Subject: v23i075: Frontend to RCS ci/co
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 9eaeecb7 56294d6f 019ba86f f56cff06
-
- Submitted-by: Jason Winters <grinch!jason>
- Posting-number: Volume 23, Issue 75
- Archive-name: cio
-
- [ Save this; I hope to be posting RCS shortly... --r$ ]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: Makefile cio.c cio.man
- # Wrapped by rsalz@litchi.bbn.com on Wed Dec 5 12:19:58 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive."'
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(315 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X
- X#
- X# makefile for cio.c
- X#
- X
- XCFLAGS= -O
- XLDFLAGS=
- XLIBS=
- X
- XCFILES= cio.c
- XOBJS= cio.o
- X
- Xdefault: cio cii coo
- X
- Xcii: cio
- X ln cio cii
- X
- Xcoo: cio
- X ln cio coo
- X
- Xcio: $(OBJS)
- X cc $(LDFLAGS) -o cio $(OBJS) $(LIBS)
- X
- Xinstall: cio
- X cp cio $(HOME)/.bin/coo
- X ln $(HOME)/.bin/coo $(HOME)/.bin/cii
- X
- Xshar:
- X doshar cio.man makefile cio.c
- END_OF_FILE
- if test 315 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'cio.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cio.c'\"
- else
- echo shar: Extracting \"'cio.c'\" \(46876 characters\)
- sed "s/^X//" >'cio.c' <<'END_OF_FILE'
- X/*----------------------------------------------------------------------------
- X/ cio.c - This is a C program to replace the over-grown shell script
- X/ that started as something small...
- X/
- X/ Authors: Jason P. Winters and Craig J. Kim
- X/
- X/ We hereby declare this software to be Public Domain. That means we don't
- X/ care what you do with it. We _would_ prefer that you at least leave our
- X/ names in it, as befits Authors, but we can't force you. Of course, since
- X/ it's public domain, all risks/gains using it are your problems. You don't
- X/ have any reason to call us up and complain about it deleting 30megs of
- X/ your source code without telling you. ( Software should at least *tell* you
- X/ when it does something like that, right? ) :)
- X/
- X/ Start Date: November 23, 1988
- X/ Revisions: 29-Nov-88 jpw - initial coding completed.
- X/ 29-Nov-88 cjk - rewrite of front-end logic
- X/ 30-Nov-88 jpw - Added signals, cleanup of temp files.
- X/ 30-Nov-88 cjk - added -N option
- X/ 01-Dec-88 cjk - added usage
- X/ 01-Dec-88 jpw - added SUID controls for secure files.
- X/ 02-Dec-88 jpw - added -A option
- X/ 05-Dec-88 cjk - added '~' commands for message entering
- X/ 05-Dec-88 cjk - fixed cp to check file status before copying
- X/ 06-Dec-88 cjk - use separate process for user file input
- X/ 06-Dec-88 jpw - source now passes System V.2 lint
- X/ 07-Dec-88 cjk - added environment variable check routine
- X/ 20-Dec-88 cjk - chmod files in source dir to 0640
- X/ 21-Dec-88 cjk - put RCS header if not exists
- X/ 08-Mar-89 cjk - SCCS version
- X/ 02-Oct-89 jpw - Fixed parsing for header type to insert
- X/ Fixed small bug in directory creation routine
- X/ 10-May-90 jpw - Changed st += sprintf() code to allow for
- X/ broken sprint() calls. Failed on Sun
- X/ machines.
- X/
- X/ Known bugs:
- X/ On some systems, the Control-D as end of input in the log entry
- X/ routines will cause stdin to be closed, which means the next call
- X/ to get an entry (such as a Title file) will fail. A call to clearerr()
- X/ has been added to fix this, but it has not been tested.
- X/
- X/ To be done:
- X/ 1. When -U is used, the destination directory should be created if
- X/ it does not exist already. Also, the file mode should be changed to
- X/ 0640 so that overwriting is not possible by anyone other than
- X/ $RCSOWN for security.
- X/ 2. Full "interactive" mode support
- X/ 3. Actually use the SCCS version. (Ugh!)
- X/---------------------------------------------------------------------------*/
- X
- X/*#define DEBUG /* wanna know what's goin' on? */
- X/*#define INTERACTIVE /* enable -I option (incomplete) */
- X/*#define void int /* if system can't handle void types. */
- X#define V_RCS /* RCS version */
- X/*#define V_SCCS /* SCCS version */
- X
- X/*--------------------------------------------------- includes -------------*/
- X#include <stdio.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <errno.h>
- X#include <signal.h>
- X
- X/*--------------------------------------------------- externals ------------*/
- Xextern int errno; /* error code set by system library routines */
- X
- Xextern FILE *fopen(); /* open a stream (should be in stdio.h) */
- Xextern FILE *popen(); /* open a pipe (should be in stdio.h) */
- Xextern char *getenv(); /* read an environment variable */
- Xextern char *tmpnam(); /* create a temporary file name */
- Xextern char *mktemp(); /* create temp file with a template */
- Xextern char *malloc(); /* allocate a chunk of memory */
- Xextern char *getcwd(); /* get current directory */
- Xextern int unlink(); /* unlink (delete) a file */
- Xextern void exit(); /* define these for LINT!!!! */
- Xextern void perror(); /* define these for LINT!!!! */
- Xextern void free(); /* define these for LINT!!!! */
- X
- X/*--------------------------------------------------- defines --------------*/
- X#ifndef TRUE
- X# define TRUE 1
- X# define FALSE 0
- X#endif
- X
- X#define TYPE_LOG 0 /* log message */
- X#define TYPE_TITLE 1 /* title message */
- X#define MAX_LOG 1020 /* max # of characters for a log */
- X
- X/*--------------------------------------------------- forwards -------------*/
- Xvoid usage(/*_ void _*/); /* print program usage message */
- Xint getfinput(/*_ char *name, int type _*/); /* get title file */
- Xint child_getfinput(/*_ char *name, int type _*/); /* actual get file */
- Xvoid doincmds(/*_ char *argv[], int argc, int in _*/); /* perform user wish */
- Xvoid do_ciodir(/*_ char *filenm _*/); /* do user wish in recursive if -R */
- Xint cio(/*_ char *filenme _*/); /* the work horse */
- Xint addrcsext(/*_ char *fname _*/); /* add RCS file name extension */
- Xint rmrcsext(/*_ char *fname _*/); /* remove RCS file name extension */
- Xvoid inshdr(/*_ char *fname _*/); /* insert RCS header */
- Xint makedir(/*_ char *path _*/); /* make a directory and all its parent */
- Xchar *strstr(/*_ char *s1, char *s2 _*/); /* find a string within a string */
- Xchar *strlwr(/*_ char *s _*/); /* convert upper case to lower */
- Xint asciifile(/*_ char *filename _*/); /* check file type */
- Xint rcsfile(/*_ char *filename _*/); /* check file is RCS file */
- Xint strrd(/*_ char *buf, int max_size, FILE *fle _*/);/* read from a file */
- Xvoid getdir(/*_ void _*/); /* obtain necessary directory information */
- Xint fix_envstr(/*_ char *cs _*/); /* remove leading/trailing blanks, etc. */
- Xvoid getrcsdir(/*_ char *dir _*/); /* build rcs dir out of working */
- Xvoid getworkdir(/*_ char *dir _*/); /* build working dir out of rcs */
- Xvoid getsrcdir(/*_ char *dir _*/); /* build source dir out of working */
- Xchar *justname(/*_ char *fpath _*/); /* return just filename portion */
- Xchar *memalloc(/*_ int size _*/); /* allocate memory and check for success */
- Xvoid sigcleanup(/*_ void _*/); /* cleanup in case interrupt */
- Xvoid get_final_id(/*_ void _*/); /* get user id of RCS file owner */
- Xint nextent(/*_ FILE *fp _*/); /* read next entry from /etc/passwd file */
- X
- X/*--------------------------------------------------- globals --------------*/
- X#ifdef V_RCS
- Xchar *ci_cmd = "ci"; /* command to use to check in a module. */
- Xchar *co_cmd = "co"; /* command to use to check out a module. */
- X#else
- Xchar *ici_cmd = "admin"; /* command to check in a module for 1st time. */
- Xchar *ci_cmd = "delta"; /* command to check in a module. */
- Xchar *co_cmd = "get"; /* command to check out a module. */
- X#endif
- Xchar *currentdir; /* current directory. */
- Xchar *homedir; /* user's home directory. */
- Xchar *rcswrk; /* $RCSWORK. */
- Xchar *rcsown; /* $RCSOWN. */
- Xchar *rcsdir; /* $RCSDIR. */
- Xchar *srcdir; /* $RCSSRC. */
- Xchar *headdir; /* $RCSHEAD. */
- Xchar *path; /* $PATH. */
- Xchar *pwdfile = "/etc/passwd"; /* default passwd file. */
- Xchar cioopt[100]; /* large buffer for command options. */
- Xchar d_ent[90]; /* small buffer for file reads. */
- Xchar final[400]; /* final dir to pass on as destination. */
- X#ifdef V_SCCS
- Xchar finalfile[400]; /* final file without SCCS extension. */
- X#endif
- Xchar logstr[MAX_LOG + 4]; /* log string to pass. */
- Xchar title[100]; /* log string to pass. */
- Xchar cmdbuf[2400]; /* do a single file. */
- Xchar editfile[400]; /* temp edit file, makes cleanup easy. */
- Xchar pwdname[20]; /* Name found in file. */
- Xchar ftypestr[82]; /* command file(1) output. */
- Xchar cii = FALSE; /* if set, we are in check in mode. */
- Xchar recurse = FALSE; /* if set, do recursive check in/out's. */
- Xchar usertitle = FALSE; /* user specified title file. */
- Xchar interactive = FALSE; /* user friendly interactive mode. */
- Xchar allfiles = FALSE; /* set it TRUE to copy all files. */
- Xchar insertheader = FALSE; /* insert RCS header at the top of the file. */
- X#ifdef DEBUG
- Xchar noexec = TRUE; /* set it FALSE for execution mode. */
- Xchar verbose = TRUE; /* be a chatterbox. */
- X#else
- Xchar noexec = FALSE; /* set it TRUE for no execution mode. */
- Xchar verbose = FALSE; /* not a chatterbox. */
- X#endif
- Xchar updsrcdir = FALSE; /* update master source directory on cii. */
- X#ifdef V_SCCS
- Xchar do_admin = FALSE; /* set it TRUE if first check in. */
- X#endif
- Xchar *prognam; /* name of this program. */
- Xstruct stat filestat; /* file status info. */
- Xint s_currentdir; /* length of current directory. */
- Xint s_homedir; /* length of user's home directory. */
- Xint s_rcswrk; /* length of $RCSWORK. */
- Xint s_rcsdir; /* length of $RCSDIR. */
- Xint s_srcdir; /* length of $RCSSRC. */
- Xint s_path; /* length of $PATH. */
- Xint s_rcsown; /* length of $RCSOWN. */
- Xint s_headdir; /* length of $RCSHEAD. */
- Xint user_id; /* Effective user id to use if ROOT process. */
- Xint real_user_id; /* Save buffer for original user_id. */
- Xint do_unlink; /* add -l option if not set to avoid unlink of source file. */
- X
- X/*--------------------------------------------------- main() ----------------
- X/ where we begin!
- X/---------------------------------------------------------------------------*/
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X register int in;
- X register char *cp; /* used in string updates. */
- X
- X prognam = justname(argv[0]); /* program name */
- X getdir(); /* go get the enviroment pointers. */
- X
- X /*
- X * figure what the user wants us to be by reading program name
- X */
- X if (!strcmp("ciitest", prognam) || !strcmp("cootest", prognam))
- X {
- X getrcsdir(final, currentdir); /* setup variables. */
- X /*
- X * print out our variables here.
- X */
- X#ifdef V_RCS
- X (void) printf("Homedir:%s: rcsdir:%s: rcswrk:%s: rcssrc:%s:\n",
- X#else
- X (void) printf("HOME:%s: SCCSDIR:%s: SCCSWRK:%s: SCCSSRC:%s:\n",
- X#endif
- X homedir ? homedir : "",
- X rcsdir ? rcsdir : "",
- X rcswrk ? rcswrk : "",
- X srcdir ? srcdir : "");
- X (void) printf("Final dir:%s:\n", final);
- X return(0);
- X }
- X if (!strcmp("cii", prognam)) /* this is input.. */
- X cii = TRUE; /* show we are inputs. */
- X else if (strcmp("coo", prognam))/* it's not this either.. */
- X {
- X (void) printf("Just what did you think this program was, anyway??\n");
- X return(-1);
- X }
- X
- X if (!(user_id = geteuid())) /* we are a root process.. */
- X {
- X (void) umask(027); /* set general mask to private modes. */
- X real_user_id = getuid();
- X if (cii) /* only set this if we are in checkin mode. */
- X get_final_id(); /* go get the final user ID for file creation. */
- X else
- X user_id = real_user_id; /* otherwise, use owners real one. */
- X (void) setuid(user_id); /* and, fix up the user id now. */
- X#ifdef DEBUG
- X (void) printf("Using Uid:%d:\n", user_id);
- X#endif
- X }
- X else
- X real_user_id = user_id; /* else they should match. */
- X
- X /* prepare for disasters */
- X (void) signal(SIGINT, (int (*)()) sigcleanup);
- X (void) signal(SIGQUIT, (int (*)()) sigcleanup);
- X
- X cp = cioopt;
- X title[0] = '\0'; /* make sure no titles are required. */
- X for (in = 1; argv[in][0] == '-'; in++) /* while chars here.. */
- X {
- X switch ((int) argv[in][1]) /* what option? */
- X {
- X case '?': /* print program usage */
- X case '-':
- X usage();
- X return(0);
- X case 'A': /* copy all files */
- X allfiles = !allfiles;
- X break;
- X#ifdef INTERACTIVE
- X case 'I': /* interactive mode */
- X interactive = !interactive;
- X break;
- X#endif
- X case 'H': /* RCS/SCCS header */
- X insertheader = !insertheader;
- X break;
- X case 'N': /* do not execute */
- X noexec = !noexec;
- X break;
- X case 'R': /* Recursion flag. */
- X recurse = !recurse;
- X break;
- X case 'T': /* get Title flag. */
- X if(cii) /* get a title file and name. */
- X (void) getfinput(title, TYPE_TITLE);
- X break;
- X case 'U': /* update working directory */
- X updsrcdir = !updsrcdir;
- X break;
- X case 'V': /* verbose */
- X verbose = !verbose;
- X break;
- X#ifdef V_RCS
- X case 'm': /* they gave us one */
- X#else
- X case 'y': /* they gave us one */
- X#endif
- X (void) strcpy(logstr, &argv[in][1]); /* copy across. */
- X break;
- X case 't': /* user gave us one */
- X (void) strcpy(title, &argv[in][1]);
- X usertitle = TRUE;
- X break;
- X default: /* must be a ci or co command */
- X (void) sprintf(cp, " %s", argv[in]); /* append */
- X cp += strlen(cp); /* skip to end of string. */
- X break;
- X }
- X }
- X#ifdef INTERACTIVE
- X if (noexec && interactive) /* resolve conflict of interest */
- X interactive = FALSE;
- X#endif
- X doincmds(argv, argc, in); /* do the check in command. */
- X if (title[0] && !usertitle) /* if file is here. */
- X (void) unlink(title); /* zap it! */
- X return(0); /* we did it good! */
- X}
- X
- X/*--------------------------------------------------- usage() ---------------
- X/ print program usage information
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xusage()
- X{
- X char *inout = cii ? "in" : "out";
- X
- X#ifdef INTERACTIVE
- X (void) fprintf(stderr, "Usage: %s [-A] %s[-I] [-N] [-R] %s",
- X#else
- X (void) fprintf(stderr, "Usage: %s [-A] %s[-N] [-R] %s",
- X#endif
- X prognam, cii ? "[-H] " : "",
- X cii ? "[-T] [-U] " : "");
- X (void) fprintf(stderr, "[-V] [%s options] [[filename]...]\n",
- X cii ? ci_cmd : co_cmd);
- X (void) fprintf(stderr, " -A : check %s all files\n", inout);
- X#ifdef INTERACTIVE
- X (void) fprintf(stderr, " -I : interactive mode\n");
- X#endif
- X if (cii)
- X#ifdef V_RCS
- X (void) fprintf(stderr, " -H : attach RCS header\n");
- X#else
- X (void) fprintf(stderr, " -H : attach SCCS header\n");
- X#endif
- X (void) fprintf(stderr, " -N : no execute mode\n");
- X (void) fprintf(stderr, " -R : recursive check %s\n", inout);
- X if (cii)
- X {
- X (void) fprintf(stderr, " -T : create title file\n");
- X (void) fprintf(stderr, " -U : update source directory\n");
- X }
- X (void) fprintf(stderr, " -V : verbose mode\n");
- X}
- X
- X/*--------------------------------------------------- sigcleanup() ----------
- X/ cleanup before exiting.
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xsigcleanup()
- X{
- X (void) printf("\n[%s: Interrupted]\n", prognam);
- X if (title[0] && !usertitle) /* remove title file, if here. */
- X (void) unlink(title);
- X if (editfile[0]) /* if a temp file might be here. */
- X (void) unlink(editfile); /* attempt to remove it.*/
- X exit(0);
- X}
- X
- X/*--------------------------------------------------- doincmds() ------------
- X/ actual do routine
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xdoincmds(argv, argc, in)
- Xchar *argv[];
- Xint argc, in;
- X{
- X register char *cp;
- X char entry[400];
- X
- X if (cii)
- X {
- X if (argc == in) /* no arguments given */
- X {
- X do_ciodir(currentdir);
- X return /* void */;
- X }
- X for ( ; in < argc; in++)
- X {
- X (void) sprintf(entry, "%s/%s", currentdir, argv[in]);
- X#ifdef DEBUG
- X (void) printf("Processing %s\n", entry);
- X#endif
- X if (stat(entry, &filestat))
- X {
- X#ifdef DEBUG
- X (void) printf("Unable to stat(2) %s\n", entry);
- X#endif
- X continue;
- X }
- X do_unlink = (filestat.st_uid == real_user_id);
- X if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- X do_ciodir(entry);
- X else
- X (void) cio(entry);
- X }
- X }
- X else /* coo */
- X {
- X char *ep;
- X
- X getrcsdir(entry, currentdir);
- X if (argc == in)
- X {
- X do_ciodir(entry);
- X return /* void */;
- X }
- X for (ep = entry; *ep; ep++)
- X ;
- X for ( ; in < argc; in++)
- X {
- X (void) sprintf(ep, "/%s", argv[in]);
- X#ifdef DEBUG
- X (void) printf("Processing %s\n", entry);
- X#endif
- X if (stat(entry, &filestat))
- X {
- X if (!addrcsext(entry))
- X continue;
- X if (stat(entry, &filestat))
- X continue;
- X }
- X do_unlink = (filestat.st_uid == real_user_id);
- X if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- X do_ciodir(entry);
- X else
- X (void) cio(entry);
- X }
- X
- X }
- X return /* void */;
- X}
- X
- X/*--------------------------------------------------- do_ciodir() -----------
- X/ actual do routine - Warning: RECURSIVE
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xdo_ciodir(dir)
- Xchar *dir;
- X{
- X FILE *pp;
- X char *cmd, *entry;
- X
- X (void) sprintf(cmd = memalloc(strlen(dir) + 4), "ls %s", dir);
- X pp = popen(cmd, "r");
- X free(cmd);
- X if (!pp)
- X return /* void */;
- X entry = memalloc(strlen(dir) + 30);
- X while (strrd(d_ent, 80, pp) != -1)
- X {
- X (void) sprintf(entry, "%s/%s", dir, d_ent);
- X if (stat(entry, &filestat))
- X {
- X#ifdef DEBUG
- X (void) printf("Unable to stat(2) %s\n", entry);
- X#endif
- X continue;
- X }
- X do_unlink = (filestat.st_uid == real_user_id);
- X if ((filestat.st_mode & S_IFMT) == S_IFDIR)
- X {
- X if (recurse)
- X do_ciodir(entry);
- X else
- X continue;
- X }
- X else
- X (void) cio(entry);
- X }
- X free(entry);
- X (void) pclose(pp);
- X return /* void */;
- X}
- X
- X/*--------------------------------------------------- cio() -----------------
- X/ do this to file, if we can.
- X/---------------------------------------------------------------------------*/
- Xint
- Xcio(filename)
- Xchar *filename;
- X{
- X register char *cp, *st; /* some char pointers */
- X int do_copy = FALSE; /* do cp(1) */
- X char titlest[100]; /* for file names. */
- X
- X if (cii)
- X {
- X if (!asciifile(filename)) /* if not ascii file */
- X {
- X if (!allfiles)
- X return(FALSE); /* don't if not forced copy */
- X do_copy = TRUE;
- X }
- X else if (insertheader) /* inserting default header */
- X {
- X inshdr(filename);
- X }
- X }
- X else if (!rcsfile(filename)) /* not an RCS file */
- X {
- X if (!allfiles)
- X return(FALSE);
- X do_copy = TRUE; /* simply cp(1) it */
- X }
- X
- X if (cii && !do_copy && !logstr[0]) /* we don't have a log entry yet. */
- X {
- X if (noexec)
- X {
- X (void) printf("Logfile entry bypassed.\n");
- X (void) strcpy(logstr, " "); /* fake it */
- X }
- X else if (!getfinput(titlest, TYPE_LOG)) /* if we entered anything */
- X {
- X FILE *fp;
- X char buf[100];
- X register char *bp;
- X register int numchars = 0;
- X
- X if (fp = fopen(titlest, "r"))
- X {
- X st = logstr;
- X#ifdef V_RCS
- X (void) sprintf(st, " -m\"");
- X#else
- X (void) sprintf(st, " -y\"");
- X#endif
- X st += strlen(st); /* skip to end of string. */
- X while (strrd(buf, 80, fp) != -1)
- X { /*
- X * escape quotes (") characters
- X */
- X bp = buf;
- X while (*bp)
- X {
- X if (*bp == '"')
- X if (numchars < MAX_LOG)
- X {
- X numchars++;
- X *st++ = '\\'; /*escape*/
- X }
- X if (numchars < MAX_LOG)
- X {
- X numchars++;
- X *st++ = *bp++; /* append */
- X }
- X }
- X *st++ = '\n'; /* add end of line now. */
- X }
- X if (*(st - 1) == '\n')
- X *(st - 1) = '"';
- X else
- X *st++ = '"';
- X *st = '\0';
- X (void) fclose(fp);
- X if (numchars >= MAX_LOG)
- X (void) printf("Log entry truncated.\n");
- X }
- X (void) unlink(titlest); /* cleanup. */
- X }
- X }
- X
- X titlest[0] = '\0'; /* cleanup string reference. */
- X if (cii)
- X getrcsdir(final, filename);
- X else
- X getworkdir(final, filename);
- X
- X if (st = strrchr(final, '/')) /* if this has a sub dir. */
- X {
- X *st = '\0'; /* terminate it at the directoy level. */
- X if (access(final, 0)) /* it's not here... */
- X if (!makedir(final)) /* so try and make it. */
- X {
- X (void) printf("Could not create directory :%s:\n", final);
- X return(FALSE);
- X }
- X *st = '/'; /* restore the rest of the file name. */
- X }
- X
- X if (cii)
- X {
- X if (!do_copy) /* not in binary mode. */
- X { /*
- X * make the new file name and check if it's here
- X */
- X#ifdef V_SCCS
- X (void) strcpy(finalfile, final);
- X#endif
- X (void) addrcsext(final);
- X if (!noexec && access(final, 0))
- X {
- X /*
- X * if not, need to get a title message for it
- X */
- X if (!title[0]) /* no title file yet. */
- X (void) getfinput(title, TYPE_TITLE); /* get one */
- X if (title[0]) /* if we've one, build command */
- X (void) sprintf(titlest, " -t%s ", title);
- X#ifdef V_SCCS
- X do_admin = TRUE; /* 1st check-in */
- X#endif
- X }
- X#ifdef V_SCCS
- X else
- X do_admin = FALSE;
- X#endif
- X }
- X else if (noexec)
- X (void) strcpy(titlest, " -tfile_name ");
- X }
- X else /* check out mode. */
- X { /*
- X * find a comma to make the new name.
- X * if found one, strip it to make a new name.
- X */
- X (void) rmrcsext(final);
- X }
- X
- X /*
- X * Build command string
- X */
- X if (do_copy) /* we want to just copy the file now. */
- X {
- X if (!interactive && !noexec && !access(final, 0))
- X {
- X (void) printf("%s already exists. Overwrite? (yes) ", final);
- X (void) strrd(cmdbuf, 20, stdin);
- X (void) strlwr(cmdbuf);
- X if (strncmp(cmdbuf, "yes", strlen(cmdbuf)))
- X return(TRUE);
- X }
- X (void) sprintf(cmdbuf, "cp %s %s", filename, final); /* copy command */
- X }
- X else if (cii)
- X {
- X#ifdef V_RCS
- X (void) sprintf(cmdbuf, "%s%s%s%s%s %s %s",
- X ci_cmd, cioopt, titlest, logstr,
- X do_unlink ? "" : " -l", filename, final);
- X#else
- X st = cmdbuf;
- X (void) sprintf(st, "cp %s %s; ", filename, finalfile);
- X st += strlen(st); /* skip to end of string. */
- X if (cp = strrchr(final, '/'))
- X {
- X *cp = '\0';
- X (void) sprintf(st, "cd %s; ", final);
- X st += strlen(st); /* skip to end of string. */
- X *cp = '/';
- X }
- X if (do_admin)
- X {
- X (void) sprintf(st, "%s -i%s%s%s%s %s",
- X ici_cmd, justname(finalfile),
- X cioopt, titlest, logstr, justname(final));
- X st += strlen(st); /* skip to end of string. */
- X }
- X else
- X {
- X (void) sprintf(st, "%s%s%s %s",
- X ci_cmd, cioopt, logstr, justname(final));
- X st += strlen(st); /* skip to end of string. */
- X }
- X if (do_unlink)
- X {
- X (void) sprintf(st, "; rm %s", filename);
- X st += strlen(st); /* skip to end of string. */
- X }
- X#endif
- X }
- X else /* coo */
- X {
- X#ifdef V_RCS
- X (void) sprintf(cmdbuf, "%s%s %s %s",
- X co_cmd, cioopt, filename, final);
- X#else
- X st = cmdbuf;
- X (void) sprintf(st, "rm -f %s; ", final);
- X st += strlen(st); /* skip to end of string. */
- X if (cp = strrchr(filename, '/'))
- X {
- X *cp = '\0';
- X (void) sprintf(st, "cd %s; ", filename);
- X st += strlen(st); /* skip to end of string. */
- X *cp = '/';
- X }
- X addrcsext(filename);
- X (void) sprintf(st, "%s%s %s", co_cmd, cioopt,
- X justname(filename));
- X st += strlen(st); /* skip to end of string. */
- X if (cp = strrchr(final, '/'))
- X {
- X cp++;
- X (void) sprintf(st, "; mv %s %s", cp, final);
- X st += strlen(st); /* skip to end of string. */
- X }
- X#endif
- X }
- X
- X#ifdef INTERACTIVE
- X if (interactive)
- X {
- X char ans[20];
- X int done = FALSE;
- X
- X do
- X {
- X (void) printf("%s\nExecute? (yes) ", cmdbuf);
- X (void) strrd(ans, 20, stdin);
- X st = ans;
- X while (isspace(*st))
- X st++;
- X if (!*st)
- X (void) strcpy(st, "yes");
- X (void) strlwr(st);
- X if (!strncmp(st, "yes", strlen(st))) {
- X done = TRUE;
- X (void) system(cmdbuf); /* do it. */
- X }
- X else if (*st == '?')
- X {
- X (void) printf("\n");
- X (void) printf("yes Do it\n");
- X (void) printf("no Don't do it\n");
- X (void) printf("view View current file\n");
- X (void) printf("? Print this message\n");
- X (void) printf("\n");
- X }
- X else if (!strncmp(st, "view", strlen(st)))
- X {
- X (void) printf("Not implemented yet!\n\n");
- X }
- X else /* take it as "no" */
- X done = TRUE;
- X } while (!done);
- X }
- X else
- X {
- X#endif /* INTERACTIVE */
- X if (verbose)
- X (void) printf("%s command :%s:\n", prognam, cmdbuf);
- X if (!noexec)
- X {
- X if (do_copy && !verbose)
- X (void) printf("%s\n", cmdbuf);
- X (void) system(cmdbuf); /* do it. */
- X }
- X else if (!verbose) /* if don't want to exec, don't */
- X (void) printf("%s\n", cmdbuf);
- X#ifdef INTERACTIVE
- X }
- X#endif /* INTERACTIVE */
- X if (updsrcdir) /* update source directory */
- X {
- X getsrcdir(final, filename);
- X (void) sprintf(cmdbuf, "cp %s %s", filename, final);
- X if (noexec) /* don't actual do it */
- X (void) printf("%s\n", cmdbuf);
- X else
- X {
- X if (verbose) /* speak, yo wise one! */
- X (void) printf("%s command :%s:\n", prognam, cmdbuf);
- X if (!strcmp(filename, final))
- X (void) printf("Source and destination identical. Not updated.\n");
- X else
- X {
- X (void) chmod(final, 0640);
- X (void) system(cmdbuf); /* do it! */
- X }
- X }
- X }
- X return(TRUE);
- X}
- X
- X/*--------------------------------------------------- addrcsext() -----------
- X/ add RCS file extension ",v" if there isn't one already
- X/---------------------------------------------------------------------------*/
- Xint
- Xaddrcsext(fname)
- Xchar *fname;
- X{
- X register char *cp;
- X
- X#ifdef V_RCS
- X for (cp = fname; *cp; cp++)
- X ;
- X if (*--cp == 'v' && *(cp - 1) == ',')
- X return(0); /* already there */
- X
- X *++cp = ','; /* add ",v" */
- X *++cp = 'v';
- X *++cp = '\0';
- X#else
- X char t_name[20];
- X
- X cp = justname(fname);
- X if (*cp == 's' && *(cp + 1) == '.')
- X return(0);
- X (void) strcpy(t_name, cp);
- X *cp++ = 's'; /* add "s." in front of file name */
- X *cp++ = '.';
- X (void) strcpy(cp, t_name);
- X#endif
- X return(1);
- X}
- X
- X/*--------------------------------------------------- rmrcsext() ------------
- X/ remove RCS extension if there is one; returns 1 if remove, else 0
- X/---------------------------------------------------------------------------*/
- Xint
- Xrmrcsext(fname)
- Xchar *fname;
- X{
- X register char *cp;
- X
- X#ifdef V_RCS
- X for (cp = fname; *cp; cp++)
- X ;
- X if (*--cp == 'v' && *--cp == ',')
- X {
- X *cp = '\0';
- X return(1);
- X }
- X#else
- X cp = justname(fname);
- X if (*cp == 's' && *(cp + 1) == '.')
- X {
- X (void) strcpy(cp, cp + 2);
- X return(1);
- X }
- X#endif
- X return(0);
- X}
- X
- X/*--------------------------------------------------- inshdr() --------------
- X/ insert RCS header if none exists already
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xinshdr(t_name)
- Xchar *t_name;
- X{
- X# define FTYPE_C 0 /* C program text */
- X# define FTYPE_S 1 /* assembly program text */
- X# define FTYPE_SH 2 /* shell script */
- X# define FTYPE_ROFF 3 /* nroff, tbl, eqn, etc */
- X# define FTYPE_F 4 /* Fortran program text */
- X# define FTYPE_DEFAULT 5 /* don't know */
- X# define FTYPE_MK 6 /* makefile script */
- X# define FTYPE_H 7 /* C header file text */
- X
- X static struct _ftype {
- X char *keyword; /* phrase may exist in file(1) output */
- X char *header; /* header template file name. */
- X } ftype[] = {
- X#ifdef V_RCS
- X { "c program", ".rcshead.c" }, /* FTYPE_C */
- X { "assembler", ".rcshead.s" }, /* FTYPE_S */
- X { "command", ".rcshead.sh" }, /* FTYPE_SH */
- X { "roff, tbl", ".rcshead.roff" }, /* FTYPE_ROFF */
- X { "fortran", ".rcshead.f" }, /* FTYPE_F */
- X { 0, ".rcshead" }, /* FTYPE_DEFAULT */
- X { 0, ".rcshead.mk" }, /* FTYPE_MK */
- X { 0, ".rcshead.h" } }; /* FTYPE_H */
- X#else
- X { "c program", ".sccshead.c" }, /* FTYPE_C */
- X { "assembler", ".sccshead.s" }, /* FTYPE_S */
- X { "command", ".sccshead.sh" }, /* FTYPE_SH */
- X { "roff, tbl", ".sccshead.roff"}, /* FTYPE_ROFF */
- X { "fortran", ".sccshead.f" }, /* FTYPE_F */
- X { 0, ".sccshead" }, /* FTYPE_DEFAULT */
- X { 0, ".sccshead.mk" }, /* FTYPE_MK */
- X { 0, ".sccshead.h" } }; /* FTYPE_H */
- X#endif /* V_RCS */
- X static struct _fext {
- X char *name;
- X int type;
- X } fext[] = {
- X { ".c", FTYPE_C },
- X { ".h", FTYPE_H },
- X { ".s", FTYPE_S },
- X { ".f", FTYPE_F },
- X { ".man", FTYPE_ROFF },
- X { ".mk", FTYPE_MK },
- X { ".1", FTYPE_ROFF },
- X { ".2", FTYPE_ROFF },
- X { ".3", FTYPE_ROFF },
- X { ".4", FTYPE_ROFF },
- X { ".5", FTYPE_ROFF },
- X { ".6", FTYPE_ROFF },
- X { ".7", FTYPE_ROFF },
- X { ".8", FTYPE_ROFF },
- X { ".9", FTYPE_ROFF },
- X { 0, 0 } };
- X FILE *ifp, *ofp;
- X char buf[4096], headfile[128], tempfile[20], fname[40];
- X register int i, c, ft = FTYPE_DEFAULT, err=0;
- X register char *ext;
- X
- X strcpy(fname, justname(t_name)); /* copy over only name. */
- X
- X if (!(ifp = fopen(t_name, "r"))) /* quickly check for RCS header */
- X return;
- X /* we are looking for "$Header" */
- X /* within first 50 lines of the file */
- X for (i = 0; strrd(buf, 128, ifp) > 0 && i < 50; i++)
- X#ifdef V_RCS
- X if (strstr(buf, "$Header"))
- X#else
- X if (strstr(buf, "#ident"))
- X#endif
- X {
- X (void) fclose(ifp);
- X if (verbose)
- X#ifdef V_RCS
- X (void) printf("%s already has a RCS header.\n",
- X#else
- X (void) printf("%s already has a SCCS header.\n",
- X#endif /* V_RCS */
- X t_name);
- X return;
- X }
- X
- X (void) fclose(ifp);
- X /* examine file(1) output */
- X for (i = 0; ftype[i].keyword; i++)
- X if (strstr(ftypestr, ftype[i].keyword))
- X {
- X ft = i;
- X break; /* found one */
- X }
- X
- X if (!ftype[i].keyword) /* file(1) didn't help */
- X { /* examine file extension */
- X if (ext = strrchr(fname, '.'))
- X {
- X for (i = 0; fext[i].name; i++)
- X if (!strcmp(ext, fext[i].name))
- X ft = fext[i].type;
- X }
- X else
- X { /* check if makefile script */
- X (void) strcpy(buf, fname);
- X (void) strlwr(buf);
- X if (!strcmp(buf, "makefile") || !strcmp(buf, "Makefile"))
- X ft = FTYPE_MK; /* If either of two fixed names.. */
- X }
- X }
- X else if (ft == FTYPE_C) /* see if source or header */
- X {
- X if ((ext = strrchr(fname, '.')) && !strcmp(ext, ".h"))
- X ft = FTYPE_H;
- X }
- X if (verbose) /* is this necessary */
- X (void) printf("%s is type [%d]\n", fname, ft);
- X if (noexec) /* no execution mode */
- X return;
- X
- X (void) sprintf(headfile, "%s%s", headdir, ftype[ft].header);
- X if (!(ifp = fopen(headfile, "r")))
- X {
- X (void) printf("Unable to open header template file [%s]\n",
- X headfile);
- X return;
- X }
- X /* build a tmp file in the same directory as old file. */
- X strcpy(tempfile, t_name);
- X ext = justname(tempfile); /* find end of path. */
- X *ext = '\0'; /* and terminate path there. */
- X (void) strcat(tempfile, "ciotmp._XXXXXX"); /* add tmp name */
- X (void) mktemp(tempfile); /* generate temp file name */
- X if (!(ofp = fopen(tempfile, "w"))) /* open temp file */
- X {
- X (void) printf("Unable to open temporary file [%s]\n", tempfile);
- X (void) fclose(ifp);
- X return;
- X }
- X while ((c = fgetc(ifp)) != EOF) /* copy header first */
- X (void) fputc(c, ofp);
- X (void) fclose(ifp);
- X if (!(ifp = fopen(t_name, "r"))) /* open check-in file */
- X {
- X (void) printf("Unable to open [%s] for read\n", t_name);
- X (void) fclose(ofp);
- X (void) unlink(tempfile);
- X return;
- X }
- X while ((c = fgetc(ifp)) != EOF) /* append to temp file */
- X if(fputc(c, ofp) == EOF)
- X err=1; /* couldn't write error. */
- X (void) fclose(ifp); /* done */
- X (void) fclose(ofp);
- X
- X/* ok. It's hard to make sure that everthing has gone well; if we unlink
- X the src file and can't link the temp file, we could lose everthing.
- X So, if copy fails, leave temp file alone, as it may be the only copy
- X we have left! If the unlinking the original fails, we can remove the
- X copy, as we don't need it.
- X*/
- X if(!err && !unlink(t_name)) /* 'mv tempfile fname' */
- X {
- X if(!link(tempfile, t_name)) /* 'cp tempfile t_name' */
- X (void) unlink(tempfile); /* 'rm tempfile' */
- X else
- X (void) printf("Link of %s and %s failed after removing %s.\n%s not removed.\n",
- X tempfile, t_name, t_name, tempfile);
- X }
- X else
- X {
- X (void) unlink(tempfile); /* 'rm tempfile' */
- X (void) printf("Could not insert header into %s. Copy failed.\n", t_name);
- X }
- X}
- X
- X/*--------------------------------------------------- makedir() -------------
- X/ make a directory path, with recursion.
- X/ returns TRUE if successful, FALSE otherwise.
- X/
- X/ This really needs to be re-written. It works, but that's all I can really
- X/ say for it... Hey, *I* don't have mkdir() calls!
- X/---------------------------------------------------------------------------*/
- Xint
- Xmakedir(newpath)
- Xchar *newpath; /* path name to make. */
- X{
- X register char *st, *cp;
- X
- X if(!*newpath) return(FALSE); /* skip last directory attempt. */
- X cp = memalloc(strlen(newpath) + 24);
- X (void) sprintf(cp, "/bin/mkdir %s 2>/dev/null", newpath);
- X if(verbose)
- X (void) printf("calling mkdir: %s\n", cp);
- X if (noexec)
- X {
- X (void) printf("%s\n", cp);
- X free(cp);
- X return(TRUE);
- X }
- X if (system(cp)) /* it failed.. */
- X {
- X (void) strcpy(cp, newpath); /* get current one. */
- X st = strrchr(cp, '/'); /* remove one more layer.. */
- X *st = '\0'; /* terminate here. */
- X if (makedir(cp) == FALSE) /* try and build next level back. */
- X {
- X free(cp);
- X return(FALSE);
- X } /* ok, so.. it passed on back. Try this again. */
- X else if(makedir(newpath) == FALSE)
- X {
- X free(cp);
- X return(FALSE);
- X }
- X }
- X free(cp);
- X return(TRUE);
- X}
- X
- X/*--------------------------------------------------- strstr() --------------
- X/ find a substring within a string
- X/---------------------------------------------------------------------------*/
- Xchar *
- Xstrstr(s1, s2)
- Xregister char *s1, *s2;
- X{
- X register int l;
- X
- X if (l = strlen(s2))
- X for ( ; s1 = strchr(s1, s2[0]); s1++)
- X if (memcmp(s1, s2, l) == 0)
- X break;
- X return(s1);
- X}
- X
- X/*--------------------------------------------------- strlwr() ---------------
- X/ strlwr.c - convert passed string to its equivalent lowercases
- X/----------------------------------------------------------------------------*/
- Xchar *
- Xstrlwr(s)
- Xregister char *s;
- X{
- X char *op;
- X
- X for (op = s; *s; s++)
- X if (isupper(*s))
- X *s = _tolower(*s);
- X return(op);
- X}
- X
- X/*--------------------------------------------------- asciifile() -----------
- X/ check if passed file is an ascii file using file(1) command
- X/---------------------------------------------------------------------------*/
- Xint
- Xasciifile(fn)
- Xchar *fn;
- X{
- X char cmdstr[256];
- X register FILE *fp;
- X
- X (void) sprintf(cmdstr, "file %s", fn);
- X if (!(fp = popen(cmdstr, "r")))
- X return(FALSE);
- X (void) strrd(ftypestr, 80, fp); /* get a line. */
- X (void) pclose(fp); /* and done. */
- X#ifdef DEBUG
- X (void) printf("%s\n", cmdstr);
- X#endif
- X if (strstr(ftypestr, "text"))
- X return(TRUE);
- X return(FALSE);
- X}
- X
- X/*--------------------------------------------------- rcsfile() -------------
- X/ check if passed file is an RCS file using file(1) command
- X/---------------------------------------------------------------------------*/
- Xint
- Xrcsfile(fn)
- Xchar *fn;
- X{
- X char cmdstr[256];
- X register FILE *fp;
- X
- X (void) sprintf(cmdstr, "file %s", fn);
- X if (!(fp = popen(cmdstr, "r")))
- X return(FALSE);
- X (void) strrd(ftypestr, 80, fp); /* get a line. */
- X (void) pclose(fp); /* and done. */
- X#ifdef DEBUG
- X (void) printf("%s\n", cmdstr);
- X#endif
- X#ifdef V_RCS
- X if (strstr(ftypestr, "text"))
- X#else
- X if (strstr(ftypestr, "sccs"))
- X#endif
- X return(TRUE);
- X return(FALSE);
- X}
- X
- X/*--------------------------------------------------- strrd() ----------------
- X/ read from given file pointer until a line separator or end-of-file or
- X/ (len) characters excluding the terminator.
- X/---------------------------------------------------------------------------*/
- Xint
- Xstrrd(buf, len, fle)
- Xchar *buf;
- Xint len;
- XFILE *fle;
- X{
- X int c0, i0 = 0;
- X
- X while (((c0 = getc(fle)) != EOF) && c0 && c0 != '\n')
- X if(i0 < len) /* if room in buffer..*/
- X buf[i0++] = (char) c0; /* save it. */
- X buf[i0] = 0;
- X if (i0 == 0 && c0 == EOF)
- X return(-1);
- X return(i0);
- X}
- X
- X/*--------------------------------------------------- getdir() --------------
- X/ get and readin variables for later.
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xgetdir()
- X{
- X register char *cp;
- X
- X if(cp = getenv("HOME")) /* get user's home dir. */
- X {
- X (void) strcpy(homedir = memalloc(strlen(cp) + 2), cp);
- X if (!(s_homedir = fix_envstr(homedir)))
- X {
- X free(homedir);
- X homedir = (char *) 0;
- X }
- X }
- X else /* this should NEVER happen */
- X {
- X (void) fprintf(stderr, "No home directory???\n");
- X exit(-1);
- X }
- X
- X#ifdef V_RCS
- X if(cp = getenv("RCSDIR")) /* RCS directory */
- X#else
- X if(cp = getenv("SCCSDIR")) /* SCCS directory */
- X#endif
- X (void) strcpy(rcsdir = memalloc(strlen(cp) + 2), cp);
- X else /* RCS is $HOME/RCS */
- X (void) sprintf(rcsdir = memalloc(s_homedir + 6),
- X#ifdef V_RCS
- X "%s/RCS", homedir);
- X#else
- X "%s/SCCS", homedir);
- X#endif
- X if (!(s_rcsdir = fix_envstr(rcsdir)))
- X {
- X free(rcsdir);
- X rcsdir = (char *) 0;
- X }
- X
- X#ifdef V_RCS
- X if(cp = getenv("RCSWORK")) /* user's working directory */
- X#else
- X if(cp = getenv("SCCSWORK")) /* user's working directory */
- X#endif
- X {
- X (void) strcpy(rcswrk = memalloc(strlen(cp) + 2), cp);
- X if (!(s_rcswrk = fix_envstr(rcswrk)))
- X {
- X free(rcswrk);
- X rcswrk = (char *) 0;
- X }
- X }
- X
- X#ifdef V_RCS
- X if (cp = getenv("RCSSRC")) /* master source directory */
- X#else
- X if (cp = getenv("SCCSSRC")) /* master source directory */
- X#endif
- X {
- X (void) strcpy(srcdir = memalloc(strlen(cp) + 2), cp);
- X if (!(s_srcdir = fix_envstr(srcdir)))
- X {
- X free(srcdir);
- X srcdir = (char *) 0;
- X }
- X }
- X
- X#ifdef V_RCS
- X if (cp = getenv("RCSHEAD")) /* RCS header file directory */
- X#else
- X if (cp = getenv("SCCSHEAD")) /* SCCS header file directory */
- X#endif
- X {
- X (void) strcpy(headdir = memalloc(strlen(cp) + 2), cp);
- X if (!(s_headdir = fix_envstr(headdir)))
- X {
- X free(headdir);
- X headdir = homedir;
- X }
- X }
- X else
- X headdir = homedir;
- X
- X#ifdef V_RCS
- X if (cp = getenv("RCSOWN")) /* the owner of RCS files */
- X#else
- X if (cp = getenv("SCCSOWN")) /* the owner of SCCS files */
- X#endif
- X {
- X s_rcsown = strlen(cp);
- X (void) strcpy(rcsown = memalloc(s_rcsown + 1), cp);
- X }
- X
- X if(cp = getenv("PATH")) /* current path, ie. $PATH */
- X {
- X s_path = strlen(cp);
- X (void) strcpy(path = memalloc(s_path + 1), cp);
- X }
- X
- X if((currentdir = getcwd((char *)NULL, 200)) == NULL)
- X {
- X (void) fprintf(stderr, "Cannot get working dir.\n");
- X exit(-1);
- X }
- X s_currentdir = strlen(currentdir);
- X}
- X
- X/*--------------------------------------------------- fix_envstr() ----------
- X/ fix environment variable to avoid problems later.
- X/ 1. strip leading/trailing white spaces
- X/ 2. strip duplicate slashes
- X/ 3. add trailing slash
- X/ 4. return string length
- X/---------------------------------------------------------------------------*/
- Xint
- Xfix_envstr(cs)
- Xchar *cs;
- X{
- X register char *cp, *dp;
- X register int was_slash = FALSE;
- X
- X cp = dp = cs;
- X while (isspace(*cp)) /* remove leading white spaces */
- X cp++;
- X
- X if (!*cp) /* string was a full of blanks */
- X return(0);
- X
- X while (*cp)
- X {
- X if (*cp == '/')
- X {
- X if (was_slash)
- X {
- X cp++; /* strip duplicate slashes */
- X continue;
- X }
- X else
- X was_slash = TRUE;
- X }
- X else
- X was_slash = FALSE;
- X *dp++ = *cp++;
- X }
- X
- X do /* remove trailing while spaces */
- X {
- X dp--;
- X } while (isspace(*dp));
- X
- X if (*dp != '/') /* add trailing slash */
- X *++dp = '/';
- X *++dp = '\0'; /* null terminate */
- X return(strlen(cs));
- X}
- X
- X/*--------------------------------------------------- getrcsdir() -----------
- X/ get $RCSDIR + tail directory
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xgetrcsdir(tdir, sdir)
- Xchar *tdir, *sdir;
- X{
- X register char *cp = sdir;
- X
- X if(rcswrk && !strncmp(rcswrk, cp, s_rcswrk))
- X cp += s_rcswrk;
- X if(homedir && !strncmp(homedir, cp, s_homedir))
- X cp += s_homedir;
- X /*
- X * build the final directory name
- X */
- X (void) sprintf(tdir, "%s%s", rcsdir, cp);
- X}
- X
- X/*--------------------------------------------------- getworkdir() ----------
- X/ get $RCSWORK or $HOME + tail
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xgetworkdir(tdir, sdir)
- Xchar *tdir, *sdir;
- X{
- X register char *cp = sdir;
- X
- X if (rcsdir && !strncmp(rcsdir, cp, s_rcsdir))
- X cp += s_rcsdir;
- X (void) sprintf(tdir, "%s%s", rcswrk ? rcswrk : homedir, cp);
- X}
- X
- X/*--------------------------------------------------- getsrcdir() -----------
- X/ get $RCSSRC + tail
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xgetsrcdir(tdir, sdir)
- Xchar *tdir, *sdir;
- X{
- X register char *cp = sdir;
- X
- X if (rcsdir && !strncmp(rcsdir, cp, s_rcsdir))
- X cp += s_rcsdir;
- X if(homedir && !strncmp(homedir, cp, s_homedir))
- X cp += s_homedir;
- X (void) sprintf(tdir, "%s%s", srcdir ? srcdir : homedir, cp);
- X}
- X
- X/*--------------------------------------------------- getfinput() ------------
- X/ get a title file.
- X/---------------------------------------------------------------------------*/
- Xint
- Xgetfinput(name, type)
- Xchar *name; /* buffer to put file name into. */
- Xint type; /* what data we want. */
- X{
- X int stat_loc;
- X
- X (void) strcpy(name, tmpnam(editfile));
- X if (fork())
- X { /* parent just waits for the child to finish */
- X (void) wait(&stat_loc);
- X }
- X else
- X { /* child does his/her stuff */
- X (void) signal(SIGINT, SIG_DFL);
- X (void) signal(SIGQUIT, SIG_DFL);
- X exit(child_getfinput(name, type) == TRUE ? 0 : -1);
- X }
- X return((stat_loc >> 8) & 0xff);
- X}
- X
- X/*--------------------------------------------------- child_getfinput() -----
- X/ actual get title file.
- X/---------------------------------------------------------------------------*/
- Xstatic int
- Xchild_getfinput(name, type)
- Xchar *name; /* buffer to put file name into. */
- Xint type; /* what data we want. */
- X{
- X static char *input_type[2] = { "log", "title" };
- X FILE *fp, *xfp;
- X register char *st;
- X int c, done = FALSE;
- X char buf[82]; /* just larger than input buffer. */
- X
- X (void) setuid(real_user_id); /* user's real user id */
- X if((fp = fopen(name, "w")) == NULL) /* failed open. */
- X {
- X (void) unlink(name); /* remove it. */
- X name[0] = '\0';
- X (void) printf("Unable to create tmp file.\n");
- X return(FALSE);
- X }
- X (void) printf("Enter %s message, <ret>.<ret> or Control-D to end:\n",
- X input_type[type]);
- X while (!done)
- X {
- X (void) printf(">>");
- X if(strrd(buf, 80, stdin) == -1) /* read in one line. */
- X {
- X /* ok, read somewhere that this is possible. By doing this,
- X we should be able to continue after a control-D.
- X */
- X clearerr(stdin);
- X break;
- X }
- X if(!strcmp(".", buf)) /* end of message */
- X break;
- X if (buf[0] == '~') /* special command */
- X {
- X switch (buf[1]) /* command character */
- X {
- X case '?': /* print usage, help message */
- X (void) printf("\n");
- X (void) printf("~. End of input\n");
- X (void) printf("~! Invoke shell\n");
- X (void) printf("~e Edit message using an editor\n");
- X (void) printf("~p Print message buffer\n");
- X (void) printf("~r Read in a file\n");
- X (void) printf("~w Write message to a file\n");
- X (void) printf("~? Print this message\n");
- X (void) printf("\n");
- X break;
- X case '!': /* shell */
- X st = getenv("SHELL");
- X (void) system(st ? st : "/bin/sh");
- X (void) printf("[Press RETURN to continue]");
- X (void) strrd(buf, 20, stdin);
- X break;
- X case 'p': /* print message buffer content */
- X (void) fclose(fp);
- X fp = fopen(name, "r");
- X while ((c = fgetc(fp)) != EOF)
- X (void) fputc(c, stdout);
- X (void) fclose(fp);
- X fp = fopen(name, "a");
- X (void) printf("Continue entering %s message.\n",
- X input_type[type]);
- X break;
- X case 'e': /* editor */
- X case 'v': /* visual */
- X (void) fclose(fp);
- X st = getenv(buf[1] == 'e' ?"EDITOR":"VISUAL");
- X (void) sprintf(buf, "%s %s",
- X st ? st : "/usr/bin/vi", name);
- X (void) system(buf);
- X fp = fopen(name, "a");
- X (void) printf("Continue entering %s message.\n",
- X input_type[type]);
- X break;
- X case 'r': /* read in a file */
- X st = &buf[2];
- X while (isspace(*st))
- X st++;
- X if (!*st)
- X {
- X (void) printf("File name missing!\n");
- X break;
- X }
- X if (xfp = fopen(st, "r"))
- X {
- X while ((c = fgetc(xfp)) != EOF)
- X (void) fputc(c, fp);
- X (void) fclose(xfp);
- X }
- X else
- X (void) printf("Unable to open %s.\n",
- X st);
- X break;
- X case 'w': /* write message to a file */
- X st = &buf[2];
- X while (isspace(*st))
- X st++;
- X if (!*st)
- X (void) printf("File name missing!\n");
- X else
- X {
- X if (xfp = fopen(st, "a"))
- X {
- X (void) fclose(fp);
- X fp = fopen(name, "r");
- X while ((c = fgetc(fp)) != EOF)
- X (void) fputc(c, xfp);
- X (void) fclose(xfp);
- X (void) fclose(fp);
- X fp = fopen(name, "a");
- X }
- X else
- X (void) printf("Unable to open %s.\n",
- X st);
- X }
- X break;
- X case '.': /* end of message */
- X done = TRUE;
- X break;
- X default: /* user doesn't know */
- X (void) printf("Unrecognized command %c -- ignored\n",
- X buf[1] & 0x7f);
- X break;
- X }
- X continue;
- X }
- X (void) fprintf(fp, "%s\n", buf);
- X }
- X (void) fclose(fp);
- X (void) printf("\n");
- X return(TRUE);
- X}
- X
- X/*--------------------------------------------------- justname() ------------
- X/ extract just filename from a full path
- X/---------------------------------------------------------------------------*/
- Xchar *
- Xjustname(fpath)
- Xchar *fpath;
- X{
- X register char *cp;
- X
- X if (cp = strrchr(fpath, '/'))
- X return(++cp);
- X
- X return(fpath);
- X}
- X
- X/*--------------------------------------------------- memalloc() ------------
- X/ allocate specified amount of memory. If not successful, exit.
- X/---------------------------------------------------------------------------*/
- Xchar *
- Xmemalloc(size)
- Xregister int size;
- X{
- X register char *cp;
- X
- X if (!(cp = malloc((unsigned)size)))
- X {
- X perror(prognam);
- X exit(99);
- X }
- X return(cp);
- X}
- X
- X/*--------------------------------------------------- get_final_id() --------
- X/ Get the RCSOWN user id to create files with. If none found, use user id.
- X/---------------------------------------------------------------------------*/
- Xvoid
- Xget_final_id()
- X{
- X FILE *fp;
- X
- X if(!rcsown) /* if there isn't one of these. */
- X#ifdef V_RCS
- X rcsown = "rcsfiles"; /* default name. */
- X#else
- X rcsown = "sccsfiles"; /* default name. */
- X#endif
- X
- X if ((fp = fopen (pwdfile, "r")) == NULL)
- X {
- X#ifdef DEBUG
- X (void) fprintf(stderr, "setpwent: %s non-existant or unreadable.\n",
- X pwdfile);
- X#endif
- X user_id = real_user_id; /* make sure it's owners id now. */
- X return; /* couldn't do it. */
- X }
- X while (nextent(fp)) /* while entries in file.. */
- X if (!strcmp(pwdname, rcsown)) /* If name matches. */
- X break;
- X (void) fclose(fp); /* close the file. */
- X return; /* found it or not, return. */
- X}
- X
- X/*--------------------------------------------------- nextent() -------------
- X/ get one entry from a password file. Return TRUE if there is one found,
- X/ FALSE otherwise.
- X/---------------------------------------------------------------------------*/
- Xint
- Xnextent(fle)
- XFILE *fle; /* file pointer. */
- X{
- X register char *cp, *pwp;
- X char savbuf[200]; /* usually large enough for a password entry. */
- X
- X while (strrd(savbuf, (int) (sizeof (savbuf)), fle) != -1)
- X {
- X pwp = pwdname;
- X cp = savbuf; /* get user name */
- X while (*cp && *cp != ':')
- X *pwp++ = *cp++;
- X *pwp = '\0'; /* terminate name. */
- X for (cp++; *cp && *cp != ':'; cp++)
- X ; /* skip over password. */
- X user_id = atoi(++cp); /* ok, save this users id number. */
- X return (TRUE);
- X }
- X user_id = real_user_id; /* make sure it's owners id now. */
- X return (FALSE);
- X}
- X
- X/*----------------------------- End of cio.c -------------------------------*/
- END_OF_FILE
- if test 46876 -ne `wc -c <'cio.c'`; then
- echo shar: \"'cio.c'\" unpacked with wrong size!
- fi
- # end of 'cio.c'
- fi
- if test -f 'cio.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cio.man'\"
- else
- echo shar: Extracting \"'cio.man'\" \(10965 characters\)
- sed "s/^X//" >'cio.man' <<'END_OF_FILE'
- X.TH CIO 1
- X.SH NAME
- Xcio - a pair of RCS user interface programs
- X.SH SYNOPSIS
- X.P 1
- Xcii [cii options] [ci options] [filename ...] [dirname ... ]
- X.P 1
- Xcoo [coo options] [co options] [filename ...] [dirname ... ]
- X.SH DESCRIPTION
- X.I Cii
- Xand
- X.I coo
- Xare two programs that will provide an interface to the RCS programs
- X.I ci
- Xand
- X.I co.
- XThey add:
- X.P 1
- XRecursively check in/out directory structures
- X.P 1
- XStore RCS files in a separate directory structure
- X.P 1
- XDefault stores only ASCII files, enabling program to
- Xbe run on directories with both source and binary
- X.sp
- X.PP
- XCommand line options include:
- X.TP 5
- X.B -A
- XAll files. Forces a "cp" of files that are non-ASCII.
- X.TP 5
- X.B -H
- XInsert RCS header. If a valid RCS header not found, a template header
- Xwill be inserted at the beginning of the file being checked in.
- X.TP 5
- X.B -N
- XNo operation. Causes
- X.I cii
- Xor
- X.I coo
- Xto display the action that would have resulted. Nothing is executed.
- X.TP 5
- X.B -R
- XRecursively walk down directories to check in/out
- X.TP 5
- X.B -T
- XForce title request at start of program (Default only gets title
- Xwhen required.)
- X.TP 5
- X.B -U
- XUpdate source directory. During a check-in, a copy is made to the
- Xdirectory structure specified by $RCSSRC. If $RCSSRC is not defined,
- X$HOME will be used instead.
- X.TP 5
- X.B -V
- XVerbose. Be real talkative about the work being done.
- X.TP 5
- X.B [all ci/co options]
- XPasses all other options on to
- X.I ci
- Xor
- X.I co.
- X.TP 5
- X.B filename
- XOptional file names. If not provided, the
- X.I cii
- Xprogram will take all files in the current directory, or
- X.I coo
- Xwill take all files saved in the RCS directory.
- X(Binary files only if -A was also specified.)
- X.TP 5
- X.B dirname
- XBoth programs will take a directory name as an argument, however: the
- X-R option must also be specified for it to work.
- X.sp 4
- X.SH ENVIRONMENT
- X.TP 5
- X.B RCSDIR
- XIf defined, names a path that will be used to store the RCS files. Default
- Xis $HOME/RCS. Final path is computed by removing $HOME and/or $RCSWORK
- Xfrom current path.
- X.sp
- X.TP 5
- X.B RCSWORK
- XIf defined, an alternate prefix for current working directory. Allows
- Xhaving multiple directory structures with different prefix's.
- X.sp
- X.TP 5
- X.B HOME
- XMust be defined as the users home directory.
- X.sp
- X.TP 5
- X.B RCSSRC
- XIf defined and -U flag is specified, during a
- X.I cii
- Xprocedure, a copy of
- Xwhat's being checked in will be made in the directory structure starting
- Xat $RCSSRC. If not specified,
- X.I cii
- Xuses $HOME instead.
- X.sp
- X.TP 5
- X.B RCSHEAD
- XIf -H flag is specified,
- X.I cii
- Xfinds template header from $RCSHEAD directory.
- X.sp
- X.SH SAMPLES
- X.P 1
- XA user with a home directory of /usr/bog, has a directory structure called
- Xsample/arix. He want's to store all of the files in /usr/bog/sample/arix
- Xinto the RCS system. If neither RCSDIR or RCSWORK is defined, the RCS
- Xpath defaults to his home directory, followed by RCS, followed by the
- Xcurrent path. So:
- X
- X.DS
- X Current directory : /usr/bog/sample/arix
- X Home directory : /usr/bog
- X RCSDIR :
- X RCSWORK :
- X RCSSRC :
- X
- X Final RCS storage : /usr/bog/RCS/sample/arix
- X Final source storage: /usr/bog/sample/arix
- X.DE
- X.P 1
- XThe net effect of this command is to create the RCS directory, then to
- Xduplicate the directory structure in a defined place. In this case, since
- Xthe RCSDIR was not defined, it defaulted to the users home directory.
- X.P 1
- XIt is not necessary to build the directories in RCS, the program will
- Xbuild all necessary directories (Including the RCS dir, if needed).
- X.P 1
- XAnother example: All RCS files should reside in /usr/RCS, so the
- Xabove example turns into:
- X
- X.DS
- X Current directory : /usr/bog/sample/arix
- X Home directory : /usr/bog
- X RCSDIR : /usr/RCS
- X RCSWORK :
- X RCSSRC :
- X
- X Final RCS storage : /usr/RCS/sample/arix
- X Final source storage: /usr/bog/sample/arix
- X.DE
- X.P 1
- XHere is an example showing use of the RCSWORK variable. Some systems
- Xmay have more than one person working on file. In this case, the path
- Xnames will have to be similar, but only to a point. Example, /usr/tog
- Xis also working in a directory, called sample/arix. His system would look
- Xlike:
- X
- X.DS
- X Current directory : /usr/tog/sample/arix
- X Home directory : /usr/tog
- X RCSDIR : /usr/RCS
- X RCSWORK :
- X RCSSRC :
- X
- X Final RCS storage : /usr/RCS/sample/arix
- X Final source storage: /usr/tog/sample/arix
- X.DE
- X.P 1
- XNote that the RCS dir is the same for him. Now, let's take a user who
- Xhas decided to work somewhere other than his home directory.
- X
- X.DS
- X Current directory : /usr/src/rog/sample/arix
- X Home directory : /usr/rog
- X RCSDIR : /usr/RCS
- X RCSWORK : /usr/src/rog
- X RCSSRC :
- X
- X Final RCS storage : /usr/RCS/sample/arix
- X Final source storage: /usr/rog/sample/arix
- X.DE
- X.P 1
- XIf RCSSRC is specified to keep the current source (very useful to
- Xwhen one wants to browse through the current source files) in a
- Xdirectory other than his HOME.
- X
- X.DS
- X Current directory : /usr/src/rog/sample/arix
- X Home directory : /usr/rog
- X RCSDIR : /usr/RCS
- X RCSWORK : /usr/src/rog
- X RCSSRC : /usr/group
- X
- X Final RCS storage : /usr/RCS/sample/arix
- X Final source storage: /usr/group/sample/arix
- X.DE
- X.P 1
- XThe RCSWORK variable was removed from the current path, before the
- Xdirectory structure was defined. Thus, it is possible to be working in
- Xjust about anywhere on the system and still use the same directory structure
- Xand RCS files.
- X
- X.P 1
- XIf you want to recover a directory (or multiple ones) into a new working
- Xdirectory, simply create whatever part of the path you need, set the
- XRCSWORK variable to be the first part of the path, and type "coo [-R]".
- X.P 1
- XExample: A new user (/usr/log) has decided to examine the sample/*
- Xfiles. Here are the steps:
- X
- X.DS
- X Current working directory: /usr/llog
- X mkdir sample
- X chdir sample
- X RCSDIR=/usr/RCS export RCSDIR
- X RCSWORK=/usr/log export RCSWORK
- X.DE
- X
- XThis is the final setup:
- X
- X.DS
- X Current directory: /usr/log/sample
- X Home directory : /usr/llog
- X RCSDIR : /usr/RCS
- X RCSWORK : /usr/log
- X
- X Final RCS storage: /usr/RCS/sample/arix
- X.DE
- X
- X.SH SECURITY
- X.ce 1
- XSecure archives
- X.P 1
- X.I Cii/coo
- Xwill also secure archives. Changing ownership of the cii
- Xor coo program to root, and making it suid will allow private archives.
- XWith this option, an additional environment variable is searched for:
- X"RCSOWN". If this is not found, the default name "rcsfiles" is used
- Xin the following step.
- X.P 1
- XThe user name is searched for in the /etc/password. If not found,
- Xthe real users UID will be used instead. In this fashion, the
- Xci and co programs will be called with the appropriate uses abilities to
- Xcreate directories, and save files. Only the user who owns the RCS files
- Xhas write ability without going through the cii or coo programs.
- X.P 1
- XThe only condition that allows the program to remain in the root owned
- Xmode is to have the rcsfiles have a root account. Otherwise, it moves out
- Xof the root as soon as it's found the user.
- X.sp
- X.SH OTHER NOTES
- X.P 1
- X.I Cii
- Xwill not unlink files not owned by the user who is checking in the files.
- XThis prevents users from deleting files not owned by them, possibly
- Xcausing harm. (I.E., checking in the /etc/passwd file.)
- X.I coo
- Xdoes not run as root, it runs as the real user. Hence, it is not possible
- Xfor a user to overwrite files or directories they normally do not have
- Xwrite access to.
- X.P 1
- X.I Cii/coo
- Xonly will allow extraction of code by the users in the same group as the
- Xuser who checked the sources in.
- X.sp
- X.P 1
- XWe highly suggest that you exmine the code in the security area if you
- Xplan on running it secure. We've tried it secure, and it seems to work.
- XHowever... We are by no means the "great U*IX hackers", so there is
- Xprobably some way to run the program that we missed that can allow others
- Xaccess to restricted files. Check it out! If you *do* find something we
- Xmissed, please send us mail.
- X.sp
- X.SH EDITOR COMMANDS
- X.P 1
- XThe input editor for the logfile entries and title file entries have
- Xtilde (~) command options available. These are:
- X.DS
- X ? - Print a help menu.
- X . - End of input.
- X ! - Invoke a user shell. Note: Shell is invoked
- X as the real user-id; No arguments are passed
- X or allowed. The ENV variable "SHELL" is
- X searched for, if not present /bin/sh will be
- X invoked.
- X e - Edit the message using a default editor.
- X Searches for the ENV variable VISUAL or
- X EDITOR. If not found, /usr/bin/vi is the
- X default editor.
- X p - Print message buffer. Displays the current
- X contents of the message buffer.
- X r - Read in a file. Requires file name as an
- X argument. Named file will be appended to
- X current buffer.
- X w - Write message to a file. Requires file name
- X as an argument. Appends message buffer to
- X file name given. If file does not exist,
- X creates file. Does not create directories.
- X.DE
- X.sp 2
- X.SH AUTHORS
- XJason P. Winters (jason@grinch.uucp) and Craig J. Kim (cjkim@aeras.uucp)
- X.SH FILES
- XThe following template files can be created to insert RCS header into
- Xsource files during
- X.I cii
- Xprocess with -H option. The location for these files is specified by
- Xsetting $RCSHEAD environment variable. If $RCSHEAD is not set, $HOME
- Xwill be used instead. File types are determined by examining the
- Xcontent via file(1) program and by file extensions (e.g. .c for C
- Xprograms, .mk for makefiles, .1 for nroff, and .s for assembly).
- X
- X.DS
- X .rcshead - default template
- X .rcshead.c - C program template
- X .rcshead.s - Assembly source template
- X .rcshead.sh - Shell script template
- X .rcshead.f - Fortran program template
- X .rcshead.mk - makefile template
- X .rcshead.h - C header file template
- X .rcshead.roff - nroff, troff, man file template
- X.DE
- X.sp
- X.SH DIAGNOSTICS
- X.P 1
- XLinking cio to ciitest or cootest will cause the program to parse the
- Xdirectory paths, and print out the final pathnames. Nothing else happens.
- XUsing the -N option will cause the program to execute as normal, except
- Xthat no files or directories will be created.
- X.sp
- X.SH BUGS
- XOn some systems, the Control-D as end of input to a log or title entry
- Xcan cause problems with STDIN. We've added a call to clearerr(), but
- Xhave not tested if that fixes it. ( It doesn't break it, so... )
- X.P 1
- XAny other bugs we would like to hear about. We might even make a new
- Xrelease, if people actually use this. :)
- X.SH AUTHOR
- XJason Winters, grinch!jason
- END_OF_FILE
- if test 10965 -ne `wc -c <'cio.man'`; then
- echo shar: \"'cio.man'\" unpacked with wrong size!
- fi
- # end of 'cio.man'
- fi
- echo shar: End of archive.
- exit 0
- exit 0 # Just in case...
-